1、看源码之前要了解的一些内容
Node<K,V>[] table;    -- 哈希表结构中数组的名字

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16  -- 数组默认长度，16

static final int MAXIMUM_CAPACITY = 1 << 30;

static final float DEFAULT_LOAD_FACTOR = 0.75f;  -- 默认加载因子/负载因子

static final int TREEIFY_THRESHOLD = 8; -- 链表树化阈值，链表长度的阈值

static final int UNTREEIFY_THRESHOLD = 6;  -- 树链表化阈值，链表长度的阈值

static final int MIN_TREEIFY_CAPACITY = 64;  -- 链表树化阈值，数组长度的阈值


HashMap中的主要对象：
1.1 链表中的键值对对象
	final int hash;    // 键的哈希值
    final K key;       // 键
    V value;           // 值
    Node<K,V> next;    // 下一个节点

1.2 红黑树中的键值对对象
	final int hash;        // 键的哈希值
    final K key;           // 键
    V value;               // 值
	TreeNode<K,V> parent;  // 父节点
	TreeNode<K,V> left;    // 左子节点
	TreeNode<K,V> right;   // 右子节点
	TreeNode<K,V> prev;    // needed to unlink next upon deletion
	boolean red;	       // 节点颜色
	
	
2、添加元素
Map<String, Integer> map = new HashMap<>();
map.put("aa", 11);
map.put("bb", 22);

添加元素的时候至少考虑三种情况：
2.1数组位置为null
2.2数组位置不为null，键重复，元素覆盖
2.3数组位置不为null，键不重复，挂在下面形成链表或者红黑树


// 返回值：被覆盖元素的值，如果没有覆盖，返回null
public V put(K key, V value) {
	return putVal(hash(key), key, value, false, true);
}

// 两个哈希值不同，key一定不同。
// 两个key相同，哈希值一定相同。
// key不同，hash值可能相同。
static final int hash(Object key) {
	int h;
	return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}


// 参数一：键的哈希值
// 参数二：键 
// 参数三：值
// 参数四：如果键重复了是否保留旧值
//			true，表示老元素的值保留，不会覆盖
//			false，表示老元素的值不保留，会覆盖
//			一般默认false
//          注意覆盖的时候，只是把新对象的value赋值给了就对象的value了，并非更换整个对象，只是值发生了更新覆盖
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
	Node<K,V>[] tab;  // 定义一个局部变量，用来记录哈希表中数组的地址
					  // 全局变量中的数组table是存在于堆里面的，而方法运行时的局部变量是在栈中，
					  // 为了避免反复去访问堆内存，所以这里创建了局部变量来代为处理
	Node<K,V> p;  // 临时的第三方变量，用来记录键值对对象
	int n;        // 表示当前数组的长度
	int i;		  // 表示数组索引
	
	if ((tab = table) == null || (n = tab.length) == 0) {
		// 1.如果当前是第一次添加数据，底层会创建一个默认长度为16，加载因子为0.75f的数组
		// 2.如果不是第一次添加数据，会看数组中的元素是否达到了扩容的条件
		//   	如果没有达到扩容条件，底层不会做任何操作
		// 		如果达到了扩容条件，底层会把数组扩容为原先的两倍，并把数据全部转移到新的哈希表中
		tab = resize();
		n = tab.length;
	}
	
	i = (n - 1) & hash; // index
	p = tab[i]; // 获取数组中对应元素的数据
	if (p == null)
		tab[i] = newNode(hash, key, value, null);
	else {
		Node<K,V> e; K k;
		
		// 等号的左边：数组中键值对的哈希值
		// 等号的右边：当前要添加键值对的哈希值
		boolean b1 = p.hash == hash;
		
		if (b1 && ((k = p.key) == key || (key != null && key.equals(k))))
			e = p;
		else if (p instanceof TreeNode)
			e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
		else {
			for (int binCount = 0; ; ++binCount) {
				if ((e = p.next) == null) {
					p.next = newNode(hash, key, value, null);
					
					// 判断当前链表长度是否超过8，如果超过8，就会调用treeifyBin
					// treeifyBin方法中还会继续判断
					// 判断数组的长度是否大于等于64
					// 如果同时满足这两个条件，就会把这个链表转为红黑树
					if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
						treeifyBin(tab, hash);
					break;
				}
				if (e.hash == hash &&
					((k = e.key) == key || (key != null && key.equals(k))))
					break;
				p = e;
			}
		}
		if (e != null) { // existing mapping for key
			V oldValue = e.value;
			if (!onlyIfAbsent || oldValue == null)
				e.value = value;
			afterNodeAccess(e);
			return oldValue;
		}
	}
	
	++modCount;
	
	// threshold：记录的就是数组的长度 * 0.75，哈希表的扩容时机，第一次实例化之后 16 * 0.75 = 12
	// size：HashMap中的键值对总个数，不是指数组长度
	if (++size > threshold)
		resize();
	afterNodeInsertion(evict);
	return null;
}